Identifying an attribute or a namespace node

By  Dimitre Novatchev
 
Language  XPath
Category designpatterns, namespace, msxml
Posted 22  Mar  2001
Updated 22  Mar  2001
 
Summary
Presented is a common technique to determine whether the type of a node is attribute or a namespace.
 
Whenever you have to perform a more general processing of an xml document, whose type is not known in advance (e.g. as in an XSL Debugger or in a XPath visualisation tool), you need to be able to determine the concrete type of a (any) node.
 
While for node types for which a node-test exists this is straightforward e.g:
 
self::* tests if the current node is an element
self::text() tests whether the current node is a text node
self::comment() tests whether the current node is a comment node
self::processing-instruction() tests whether the current node is a processing instruction
self::node() tests that the current node is all of the above or the root node
self::someName tests whether the current node is an element having the name someName
 
There isn't any straightforward way to determine if the current node is an attribute or a namespace.
 
This is because in XPath there isn't a node-test for attribute or namespace nodes.
 
If we try the following:
self::attribute
 
we are asking whether the current node is ***an element*** with name "attribute".
 
It is not possible to specify
 
self::attribute::*
 
because what follows the self:: axis name must be a test -- not another axis.
 
The same problem exists for trying to determine if a node is a namespace node.
 
Here is one solution to the attribute/namespace node-type identification problem:
 
We can use a set equasion to determine whether or not the current node is a member of the set of all attributes of its parent.
 
The set of all attributes of the parent of a node nd is:
 
(1) ../@*
 
The current node is:
 
(2) .
 
We can test if a node nd belongs to a node-set ns like this:
 
(3) count(nd | ns) = count(ns)
 
Substituting (1) and (2) in (3) we obtain:
 
count(. | ../@*) = count(../@*)
 
In the same way to test for a namespace we can use the following expression:
 
count(. | ../namespace::*) = count(../namespace::*)
 
I'm going to show how to use these two tests in my next snippet.
 
Code